package finalfrontier;

import java.io.Serializable;

import java.util.Random;
import java.util.Vector;
/**Classe AnimalCarnivore
 * @author Nicolas Roy Boourdages
 */

public class AnimalCarnivore extends CarreVieElite implements Comportement,
                                                              Serializable {
    
    private Vector<Coord> coordHerbivores;
    private Vector<Coord> coordVides;
    private Vector<Coord> coordCarnivores;
    
    private int lastFrame;
    private int lastFrameManger;
    private int lastFrameWedLock;
    private int lastFrameBouger;
    
    private int lastCasei;
    private int lastCasej;
    
    private float[] color = new float[3];
    
    private boolean wantsChildren;
    private boolean wedLock;
    private boolean veutManger;
    private boolean veutDeplacer;
    
    private int steps;
    private int index;
    
    private Coord cTemp = new Coord(0,0);
    
    public AnimalCarnivore(double d, double d1, double death, String g, long seed) {
        super(d, d1, death, g, seed);
        
        lastFrame = 0;
        lastFrameManger = -Constants.nbFramesAvantManger;
        lastFrameWedLock = 0;
        lastCasei = 0;
        lastCasej = 0;
        veutManger = true;
        veutDeplacer = true;
        wantsChildren = false;
        wedLock = false;
        steps = 1;
        
        coordHerbivores = new Vector<Coord>(Constants.VISION_RANGE_CARNIVORES * Constants.VISION_RANGE_CARNIVORES);
        coordCarnivores = new Vector<Coord>(Constants.VISION_RANGE_CARNIVORES * Constants.VISION_RANGE_CARNIVORES);
        coordVides = new Vector<Coord>(Constants.VISION_RANGE_CARNIVORES * Constants.VISION_RANGE_CARNIVORES);
    }

    public AnimalCarnivore() {
        super();
    }
    
    public float[] execute(int i, int j){
        
        if(lastFrame != DisplayWindow.frameCounter){
            //avance l'age
            vieillir();
            
            if(!wedLock){
            //check si il veut manger, attends sinon
                deciderManger();
                if(veutManger){
                    buildMiniMap(i,j);
                    
                    deciderDirection();
            
                    deciderReproduire();
                
                    essayerReproduire(i,j);
            
                    manger(i,j);
                        // si il n<a pas mange
                    deplacement(i,j);
                }
            }
            else{
                seReproduire(i,j);
            }
        
            mourir(i,j);
            
            //checkItself();
        }
        lastFrame = DisplayWindow.frameCounter;
        
        return calculateColor();
    }

    public void buildMiniMap(int i, int j){
        
        coordHerbivores.clear();
        coordCarnivores.clear();
        coordVides.clear();
        
        for (int q = -Constants.VISION_RANGE_CARNIVORES; q <= Constants.VISION_RANGE_CARNIVORES; q++){ 
            for (int w = -Constants.VISION_RANGE_CARNIVORES; w <= Constants.VISION_RANGE_CARNIVORES; w++){
                if ((i + q) >= 0 && (j + w) >= 0 && (i + q) < Constants.REAL_SIZE_X && (j + w) < Constants.REAL_SIZE_Y){
                    
                    cTemp = new Coord(i+q, j+w);
                    
                    if ( q == 0 && w == 0){
                        //do nothing-self
                    }
                    else if(WorldMap.getMapVie(i + q, j + w) != null){
                        if(WorldMap.getMapVie(i + q, j + w).getClass() == AnimalHerbivore.class){
                            this.coordHerbivores.add(cTemp);
                        }
                        else if(WorldMap.getMapVie(i + q, j + w).getClass() == AnimalCarnivore.class){
                            this.coordCarnivores.add(cTemp);
                        }
                    }
                    else {
                        this.coordVides.add(cTemp);
                    }
                }
            }
            
        }
    }
    
    public void deciderManger(){
        
        if (lastFrame - lastFrameManger > Constants.nbFramesAvantManger){
            veutManger = true;
            veutDeplacer = true;
            setEnergie(getEnergie() - Constants.energyLossCarnivoreActive);
        }
        else{
            veutManger = false;
            veutDeplacer = false;
            //perds moins d</nergie quand il ne fait rien
            setEnergie(getEnergie() - Constants.energyLossCarnivorePassive);
        }
    }
    
    public void deciderDirection(){
        if(lastFrame - lastFrameManger > Constants.nbFramesAvantChangerDirection){
            setOrientation(getRandomDirection(getOrientation()));
            lastFrameManger = DisplayWindow.frameCounter - Constants.nbFramesAvantManger;
        }
    }
    
    public void deciderReproduire(){
        if (getAge() > Constants.minAgeReproductionCarnivore){
            wantsChildren = true;
        }
        if (getAge() > Constants.maxAgeReproductionCarnivore){
            wantsChildren = false;
        }
    }
    
    public void essayerReproduire(int i,int j){
        if (wantsChildren && getEnergie() > Constants.maxEnergy / 2){
            if (coordCarnivores.size() > 0){
                if (getDistance(i,j,coordCarnivores.get(0).getX(),coordCarnivores.get(0).getY()) > 1){
                    setOrientation(getTowardsDirection(i, j, coordCarnivores.get(0).getX(), coordCarnivores.get(0).getY()));
                    veutManger = false;
                    veutDeplacer = true;
                }
                
                else if (WorldMap.getMapVie(coordCarnivores.get(0).getX(), coordCarnivores.get(0).getY()).isPregnant() == false) {
                    wedLock = true;
                    setPregnant(true);
                    veutManger = false;
                    veutDeplacer = false;
                    lastFrameWedLock = DisplayWindow.frameCounter;
                }
                
            }
            else{
            veutManger = false;
            veutDeplacer = true;
            }
        }
    }
    
    public void manger(int i, int j) {
        if (veutManger){
            
            if (coordCarnivores.size() > Constants.limiteNombreProximiteCannibalisme && getEnergie() < Constants.limiteEnergieCannibalisme){
                index = getClosest(i,j,coordCarnivores);
                WorldMap.swapAndKill(coordCarnivores.get(index).getX(), coordCarnivores.get(index).getY(), i,j);
                setEnergie(Constants.maxEnergy);
                veutManger = false;
                veutDeplacer = false;
                lastFrameManger = DisplayWindow.frameCounter;
                
            }
            if(coordHerbivores.size() > 0){
                index = getClosest(i,j,coordHerbivores);
                WorldMap.swapAndKill(coordHerbivores.get(index).getX(), coordHerbivores.get(index).getY(), i,j);
                setEnergie(Constants.maxEnergy);
                veutManger = false;
                veutDeplacer = false;
                lastFrameManger = DisplayWindow.frameCounter;
            }
        }
    }
    
  private void deplacement(int i, int j){
      if (veutDeplacer){
        
        if (getOrientation().equals("S")){
              if (j - steps >= 0 && j - steps < Constants.REAL_SIZE_Y && lastCasej != j - steps ){
                  if(WorldMap.isEmpty(i, j - steps)){
                      WorldMap.swapVie(i, j - steps, i, j);
                  
                      lastCasej = j;
                      lastFrameBouger = DisplayWindow.frameCounter;
                  
                  }
                  else{
                      setOrientation(getRandomDirection("S"));
                      
                  }
              }
              else{
                  setOrientation(getRandomDirection("S"));
                  
              }
          }
         else if (getOrientation().equals("SW")){
              if (j - steps >= 0 && j - steps < Constants.REAL_SIZE_Y && lastCasej != j - steps && i - steps >= 0 && lastCasei != i && i - steps < Constants.REAL_SIZE_X){
                  if(WorldMap.isEmpty(i - steps, j - steps)){
                      WorldMap.swapVie(i - steps, j - steps, i, j);
                  
                      lastCasej = j;
                      lastCasei = i;
                      lastFrameBouger = DisplayWindow.frameCounter;
                  
                  }
                  else{
                      setOrientation(getRandomDirection("SW"));
                  }
              }
              else{
                  setOrientation(getRandomDirection("SW"));
                  
              }
          }
          else if (getOrientation().equals("SE")){
                if (j - steps >= 0 && j - steps < Constants.REAL_SIZE_Y && lastCasej != j - steps && i + steps >= 0 && lastCasei != i && i + steps < Constants.REAL_SIZE_X){
                    if(WorldMap.isEmpty(i + steps, j - steps)){
                        WorldMap.swapVie(i + steps, j - steps, i, j);
                    
                        lastCasej = j;
                        lastCasei = i;
                        lastFrameBouger = DisplayWindow.frameCounter;
                    
                    }
                    else{
                        setOrientation(getRandomDirection("SE"));
                    }
                }
                else{
                    setOrientation(getRandomDirection("SE"));
                    
                }
            }
            else if (getOrientation().equals("N")){
                if (j + steps < Constants.REAL_SIZE_Y && lastCasej != j + steps){
                    if(WorldMap.isEmpty(i, j + steps)){
                        WorldMap.swapVie(i, j + steps, i, j);
                    
                        lastCasej = j;
                        lastFrameBouger = DisplayWindow.frameCounter;
                    }
                    else{
                        setOrientation(getRandomDirection("N"));
                    }
                }
                else{
                    setOrientation(getRandomDirection("N"));
                }
                
            }
            else if (getOrientation().equals("NE")){
                  if (j + steps >= 0 && j + steps < Constants.REAL_SIZE_Y && lastCasej != j + steps && i + steps >= 0 && i + steps < Constants.REAL_SIZE_X && lastCasei != i){
                      if(WorldMap.isEmpty(i + steps, j + steps)){
                          WorldMap.swapVie(i + steps, j + steps, i, j);
                      
                          lastCasej = j;
                          lastCasei = i;
                          lastFrameBouger = DisplayWindow.frameCounter;
                      
                      }
                      else{
                          setOrientation(getRandomDirection("NE"));
                      }
                  }
                  else{
                      setOrientation(getRandomDirection("NE"));
                      
                  }
              }
            else if (getOrientation().equals("NW")){
                  if (j + steps >= 0 && j + steps < Constants.REAL_SIZE_Y && lastCasej != j + steps && i - steps >= 0 && i - steps < Constants.REAL_SIZE_X && lastCasei != i){
                      if(WorldMap.isEmpty(i - steps, j + steps)){
                          WorldMap.swapVie(i - steps, j + steps, i, j);
                      
                          lastCasej = j;
                          lastCasei = i;
                          lastFrameBouger = DisplayWindow.frameCounter;
                      
                      }
                      else{
                          setOrientation(getRandomDirection("NW"));
                      }
                  }
                  else{
                      setOrientation(getRandomDirection("NW"));
                      
                  }
              }
              else if (getOrientation().equals("E")){
                      if (i + steps < Constants.REAL_SIZE_X && lastCasei != i + steps){
                          if(WorldMap.isEmpty(i + steps, j)){
                          WorldMap.swapVie(i + steps, j, i, j);
                          lastCasei = i;
                          lastFrameBouger = DisplayWindow.frameCounter;
                          }
                          else{
                              setOrientation(getRandomDirection("E"));
                          }
                      }
                      else{
                          setOrientation(getRandomDirection("E"));
                      }
                  }
              else if (getOrientation().equals("W")){
                  if (i - steps >= 0  && lastCasei != i - steps){
                      if(WorldMap.isEmpty(i - steps, j)){
                          WorldMap.swapVie(i - steps, j, i, j);
                          lastCasei = i;
                          lastFrameBouger = DisplayWindow.frameCounter;
                      }
                      else{
                          setOrientation(getRandomDirection("W"));
                      }
                  }
                  else{
                      setOrientation(getRandomDirection("W"));
                  }
              }
            else
            {
              setOrientation(getRandomDirection("W"));
            }
              
      }
  }
    
    public void seReproduire(int i, int j) {
        if (lastFrame - lastFrameWedLock > Constants.gestationCarnivore){
            //spawn!!!
            if(coordVides.size() > 0){
                WorldMap.setMapVie(coordVides.get(0).getX(), coordVides.get(0).getY(), new AnimalCarnivore(10.0, 0.0, getDeath(), "S", getSeed()));
                wedLock = false;
                setPregnant(false);
                setTagged(false);
            }
        }
        else{
            //wait...
            setEnergie(getEnergie() - Constants.energyLossCarnivorePassive);
        }
    
    }
    
    public void checkItself(){
        if(isTagged() && !wedLock){
            wedLock = true;
            setPregnant(true);
            lastFrameWedLock = DisplayWindow.frameCounter;
        }
    }
    
    public float[] calculateColor(){
      if (isTagged()){
          color[0] = 1f;
          color[1] = 1f;
          color[2] = 0f;
      }
      else if (isPregnant()){
          color[0] = 1f;
          color[1] = 0.1f;
          color[2] = 1f;
      }
      
      else{
          color[0] = (float)(getEnergie() / Constants.maxEnergy);
          color[1] = 0f;
          color[2] = 0f;
      }
      return color;
    }
}
